/************************************************************************/
/*    Author: Scott Bevin   
-Chris I made some minor changes */
/************************************************************************/

#include "XFramework.h"
#include "XGameEntities\GameEntityManager.h"

namespace XF
{
#ifndef X_CONSOLE_POSSIBLE
#define X_CONSOLE_POSSIBLE
#endif

	Application::Application()
	{
		mQuitGame = false;
		mOgre = NULL;
		mTimer = NULL;
		mInput = NULL;
		mGameComponents = new GameComponentMap();
		mDeltaScale = 1.0f;
	}

	Application::~Application()
	{
	}
	
	bool Application::InitializeFramework()
	{
		mTimer = new WindowsTimer();

		size_t windowHnd;

		Random::Seed();

		mOgre->GetRenderWindow()->getCustomAttribute("WINDOW", &windowHnd);
		mInput = new OISInput(windowHnd);	
		mInput->Initialize();

		Logger::GetInstance()->Log("XApplicaion: framework initialized");
		return true;
	}

	bool Application::InitializeGraphics(std::string windowTitle, std::string resourceFile, bool initialiseResources)
	{

		mOgre = new OgreRenderer();

		if(!mOgre->Initialize(windowTitle, resourceFile)) 
		{
			Logger::GetInstance()->Log("XApplicaion: Ogre setup failed to initialize");
			return false;
		}

		if(initialiseResources)
			mOgre->InitializeAllResources(5);

		Logger::GetInstance()->Log("XApplicaion: Graphics initialized");
		return true;
	}

	void Application::InitializeComponents()
	{
		QuickAndDirtyOgreDebugRenderer::InitializeStaticVersion(mOgre);

		SSELOG << "XApplication: Initializing components: ";

		GameComponentListIt it;

		for(it = mGameComponentsList.begin(); it != mGameComponentsList.end(); ++it)
		{
			SystemComponent *comp = (*it);
			std::string result = "XApplication: Succesfully Init component: ";
			if(!comp->Initialised())
			{
				if(!comp->Initialise())result = "ERROR XApplication:failed to init component: ";
			}

			ILOG << result << typeid(*comp).name();
		}
	}

	void Application::Run()
	{
		while(!mQuitGame)
		{
			//Ogre::WindowEventUtilities::messagePump(); //enables window going in/out of focus (Chris)

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
			MSG msg;
			while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
			{
				 if (msg.message == WM_QUIT)
					 this->ShutDown();
				 else 
				 {
					 TranslateMessage(&msg);
					 DispatchMessage(&msg);
				 }
			}
#endif

			mTimer->update();

			double dT = mTimer->getDeltaTime() * mDeltaScale;
			
			GameComponentMapIt it;

			mInput->Update();

			QuickAndDirtyOgreDebugRenderer::GetInstance()->Begin();

			XF::GameEntityManager::GetInstance()->CleanupDeads();

			OnHandleInput(dT, mInput);

			XF::GameEntityManager::GetInstance()->HandleInput(dT, mInput);

			for(it = mGameComponents->begin(); it != mGameComponents->end(); ++it)
				(*it).second->HandleInput(dT, mInput);

			OnUpdate(dT);

			XF::GameEntityManager::GetInstance()->Update(dT);

			for(it = mGameComponents->begin(); it != mGameComponents->end(); ++it)
				(*it).second->Update(dT);

			QuickAndDirtyOgreDebugRenderer::GetInstance()->End();

			mOgre->GetRoot()->renderOneFrame();			
		}

		SSELOG << "XApplication: Exiting Run Loop";
	}

	void Application::ShutDown()
	{
		SSELOG << "Shutting down XFramework";

		delete mTimer;
		delete mInput;

		GameComponentListRevIt it;

		for(it = mGameComponentsList.rbegin(); it != mGameComponentsList.rend(); ++it)
		{
			(*it)->ShutDown();
			delete (*it);
		}

		delete mGameComponents;

		GameSettings::ShutDown();

		XF_LOGGER->ShutDown();
		delete XF_LOGGER;

		mOgre->ShutDown();
		delete mOgre;

		QuickAndDirtyOgreDebugRenderer::KillStaticVersion();
	}

	void Application::AddComponent(SystemComponent *component, std::string componentName)
	{
		if(mGameComponents->find(componentName) == mGameComponents->end())
		{
			mGameComponents->insert(std::make_pair(componentName, component));
			mGameComponentsList.push_back(component);

			ILOG << "XFramework: Component added - " << componentName;
		}
	}

	SystemComponent* Application::GetComponent(std::string componentName)
	{
		GameComponentMapIt it = mGameComponents->find(componentName);

		if(it != mGameComponents->end())
		{
			return it->second;
		}

		return NULL;
	}

	void Application::RemoveComponent(SystemComponent *component)
	{
		GameComponentMapIt it;

		for(it = mGameComponents->begin(); it != mGameComponents->end(); ++it)
		{
			if((*it).second == component)
			{
				ILOG << "XApplication: Removing component - " << it->first;

				mGameComponents->erase(it);
				mGameComponentsList.remove(component);
				
				delete it->second;
			}
		}
	}

	bool Application::Initialize( std::string windowTitle, std::string resourceFile, bool initialiseResources)
	{
		XF::Logger::GetInstance()->OnLogMessage.RegisterMethod<Application,&Application::LogToCout>(this);// chris i added this...

		SSELOG << "Initializing XFramework";

		GameSettings::Initialise(CONFIG_FILES+"Settings.cfg");
		GameEntityManager::Initialize(CONFIG_FILES+"EntityScripts.cfg");

		if(! InitializeGraphics(windowTitle, resourceFile, initialiseResources)) 
			return false;

		if(! InitializeFramework()) 
			return false;

		AddDefaultComponents();

		if(!OnInitialise())
		{
			SSELOG << "XApplicaion: " << "OnInitialise() returned false, shutting down.";
			return false;
		}

		InitializeComponents();
	
		PostInitializeComponents();
		

		SSELOG << "XFramework initialized";

		XF::Logger::GetInstance()->OnLogMessage.UnregisterMethod<Application,&Application::LogToCout>(this); //...and this so that it logs to cout during enigne init

		return true;
	}
	void Application::LogToCout( std::string message )
	{
		std::cout << message << "\n";
	}
	void Application::AddDefaultComponents()
	{
		this->AddComponent(new PostOffice(this), "Post Office");		
		this->AddComponent(new XF::CEGUIComponent(this, GetRenderer()->GetRenderWindow(), GetRenderer()->GetDefaultSceneManager(),GetRenderer()->GetRoot()), "GUI");
		this->AddComponent(new DebugVariableTracker(this), "DebugVariableTracker");		
		this->AddComponent(new RendererGameComponent(this, GetRenderer()), "Renderer");			
	}
}
